# 1、TCP协议的特点
    # 1.面向连接：是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”，这样能建立可靠的连接。建立连接，是为数据的可靠传输打下了基础。
    # 2.仅支持单播传输：每条TCP传输连接只能有两个端点，只能进行点对点的数据传输，不支持多播和广播传输方式。
    # 3.面向字节流：TCP不像UDP一样那样一个个报文独立地传输，而是在不保留报文边界的情况下以字节流方式进行传输。
    # 4.可靠传输：对于可靠传输，判断丢包，误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠，就给每个包一个序号，同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK)；如果发送端实体在合理的往返时延(RTT)内未收到确认，那么对应的数据（假设丢失了）将会被重传。
    # 5.提供拥塞控制：当网络出现拥塞的时候，TCP能够减小向网络注入数据的速率和数量，缓解拥塞
    # 6.TCP提供全双工通信：TCP允许通信双方的应用程序在任何时候都能发送数据，因为TCP连接的两端都设有缓存，用来临时存放双向通信的数据。当然，TCP可以立即发送一个数据段，也可以缓存一段时间以便一次发送更多的数据段（最大的数据段大小取决于MSS）

# 2、UDP协议的特点
    # 1.UDP是无连接的，即发送数据之前不需要建立连接（当然，发送数据结束时也没有连接可以释放），因此减少了开销和发送数据之前的时延。
    # 2.UDP使用尽最大努力交付，即不保证可靠交付，因此主机不需要维持复杂的连接状态表（这里面有很多参数）。
    # 3.UDP是面向报文的。发送方的UDP对应用程序交下来的报文，在添加首部后就向下交付IP层。UDP对应用层交下来的报文，既不合并，也不拆分，而是保留这些报文的边界。这就是说，应用层交给UDP多长 的报文，UDP就照样发送，即一次发送一个报文。
    # 4.UDP没有拥塞控制，因此网络出现的拥塞不会使源主机的发送速率降低。但是不使用拥塞控制功能的UDP有可能会引起网络产生严重的拥塞问题。
    # 5.UDP支持一对一、一对多、多对一和多对多的交互通信。
    # 6.UDP的首部开销小，只有8个字节，比TCP的20个字节的首部还要短。

# 3、SOCK_STREAM 有以下几个特征：
    # 1.数据在传输过程中不会消失；
    # 2.数据是按照顺序传输的；
    # 3.数据的发送和接收不是同步的（有的也称“不存在数据边界”）。
# SOCK_DGRAM 有以下几个特征：
    # 1.强调快速传输而非传输顺序；
    # 2.传输的数据可能丢失也可能损毁；
    # 3.限制每次传输的数据大小；
    # 4.数据的发送和接收是同步的（有的也称“存在数据边界”）。

# 4、TCP收发信息
# TCP接收端（服务端）接收步骤：
    # 1.创建套接字
    # 2.绑定端口
    # 3.设置监听
    # 4.接受连接
    # 5.接收信息
    # 6.发送应答信息（可有可无）
    # 7.关闭套接字（服务器端一般不关闭）
import socket
# 1.创建套接字：SOCK_STREAM 流格式套接字，也叫“面向连接的套接字”，即使用tcp协议
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.绑定端口：
# 127.0.0.1本地回环地址，可以跟同一内网的其他ip通信
# 端口号: 1~1024 系统专用,1024 ~8000软件占用，8000~ 65535可以用于我们调试
tcp_server.bind(('127.0.0.1',8080))
# 3.设置监听：同时监听数，服务端可以接受N个链接,但是只能同一时刻回应5个请求.
tcp_server.listen(5)
# 4.接受连接：# 等待接入，没有接入就阻塞一直等待
client_conn,client_address = tcp_server.accept()
print(client_conn)# 管道
print('客户端:', client_address)
# 5.接收信息：每次最多接受1024个字节
receive_data = client_conn.recv(1024)
print('message:',receive_data.decode('utf-8'))
# 6.发送应答信息（可有可无）
client_conn.send('tcp通信客户端接受到信息，回复'.encode())
# 7.关闭套接字（服务器端一般不关闭）
tcp_server.close()

# TCP发送端（客户端）发送步骤：
    # 1.创建套接字
    # 2.建立连接
    # 3.发送信息
    # 4.接收响应信息（可有可无）
    # 5.关闭套接字
import socket
# 1.创建套接字
tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.建立连接：地址为服务端的ip和端口
tcp_client.connect(('127.0.0.1',8080))
# 3.发送信息
tcp_client.send('tcp通信客户端发送信息'.encode('utf-8'))
# 4.接收响应信息（可有可无）
receive_data = tcp_client.recv(1024)
print('message:',receive_data.decode('utf-8'))
# 5.关闭套接字
tcp_client.close()

# 5、UDP收发信息
# TCP接收端（服务端）接收步骤：
import socket
# 1.创建一个套接字：SOCK_DGRAM 数据报格式套接字，也叫“无连接的套接字，指明使用数据协议，即使用传输层的udp协议
udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.绑定信息
udp_server.bind(('',8080))# ip地址和端口号，ip一般不用写，表示本机的任何一个ip
# 3.收发消息(优先接收)
receive_data, address= udp_server.recvfrom(1024)
print(receive_data.decode('utf-8'))
# 4.发送应答信息（可有可无）
udp_server.sendto('udp通信服务端收到信息，回复'.encode('utf-8'),address)
# 5.关闭套接字
udp_server.close()
# TCP发送端（客户端）发送步骤：
import socket

# UDP发送端（客户端）发送步骤：
# 1.创建一个套接字
udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
address = ('127.0.0.1',8080)
# 2.收发消息(优先发送)
udp_client.sendto('message: udp通信客户端发送信息'.encode('utf-8'),address)
# 3.接收响应信息（可有可无）
receive_data,receive_address = udp_client.recvfrom(1024)
print('message:',receive_data.decode('utf-8'))
# 3.关闭套接字
udp_client.close()
